package io.muoncore.spring.repository; import io.muoncore.spring.annotations.EnableMuonRepositories; import io.muoncore.spring.annotations.MuonRepository; import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.filter.AnnotationTypeFilter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import java.lang.annotation.Annotation; import java.util.HashSet; import java.util.Map; import java.util.Set; public class MuonRepositoryRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Set<String> basePackages = getBasePackages(importingClassMetadata); ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.addIncludeFilter(new AnnotationTypeFilter(MuonRepository.class)); for (String basePackage : basePackages) { Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); BeanDefinitionHolder holder = createBeanDefinition(annotationMetadata); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); } } } } private BeanDefinitionHolder createBeanDefinition( AnnotationMetadata annotationMetadata) { Map<String, Object> attributes = annotationMetadata .getAnnotationAttributes(MuonRepository.class.getCanonicalName()); String className = annotationMetadata.getClassName(); BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(MuonRepositoryFactoryBean.class); definition.addPropertyValue("type", className); String beanName = StringUtils.uncapitalize(className.substring(className .lastIndexOf(".") + 1)); return new BeanDefinitionHolder(definition.getBeanDefinition(), beanName); } protected ClassPathScanningCandidateComponentProvider getScanner() { return new ClassPathScanningCandidateComponentProvider(false) { @Override protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { if (beanDefinition.getMetadata().isIndependent()) { // TODO until SPR-11711 will be resolved if (beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().getInterfaceNames().length == 1 && Annotation.class.getName().equals( beanDefinition.getMetadata().getInterfaceNames()[0])) { try { /* Class<?> target = ClassUtils.forName(beanDefinition .getMetadata().getClassName(), MuonRepositoryRegistrar.this.classLoader); return !target.isAnnotation(); */ Class<?> target = ClassUtils.forName(beanDefinition .getMetadata().getClassName(), MuonRepositoryRegistrar.class.getClassLoader()); } catch (Exception ex) { this.logger.error("Could not load target class: " + beanDefinition.getMetadata().getClassName(), ex); } } return true; } return false; } }; } private Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) { Set<String> basePackages = new HashSet<>(); Map<String, Object> attributes = importingClassMetadata .getAnnotationAttributes(EnableMuonRepositories.class.getCanonicalName()); for (String pkg : (String[]) attributes.get("value")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (String pkg : (String[]) attributes.get("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } if (basePackages.isEmpty()) { basePackages.add(ClassUtils.getPackageName(importingClassMetadata .getClassName())); } return basePackages; } }